package com.nothing.controller;

import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Controller;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamCompositeDriver;
import com.github.sarxos.webcam.ds.buildin.WebcamDefaultDriver;
import com.github.sarxos.webcam.ds.ipcam.IpCamAuth;
import com.github.sarxos.webcam.ds.ipcam.IpCamDevice;
import com.github.sarxos.webcam.ds.ipcam.IpCamDeviceRegistry;
import com.github.sarxos.webcam.ds.ipcam.IpCamDriver;
import com.github.sarxos.webcam.ds.ipcam.IpCamMode;
import com.nothing.config.StageManager;
import com.nothing.domain.UserFaceGroup;
import com.nothing.domain.UserFaceInfo;
import com.nothing.dto.WebCamInfo;
import com.nothing.hessian.config.HessionServiceConfig;
import com.nothing.hessian.service.CheckFaceService;
import com.nothing.service.FaceEngineService;
import com.nothing.service.UserFaceImgService;
import com.nothing.service.UserFaceInfoService;
import com.nothing.service.run.CheckFace;
import com.nothing.service.run.SaveFaceImg;
import com.nothing.service.run.TakeFace;
import com.nothing.util.ExcutorUtil;
import com.nothing.view.FxmlView;
import com.xiaoleilu.hutool.lang.Validator;

import javafx.animation.ParallelTransition;
import javafx.animation.PathTransition;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Pagination;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.VLineTo;
import javafx.util.Duration;

/**
 * 调用网络摄像头
 * 
 * @author shíQíang㊚
 */
@Controller 
public class WebCamPreviewController implements Initializable{  
	
	/**
	 * Customized webcam driver.
	 */
	public static class MyCompositeDriver extends WebcamCompositeDriver {

		public MyCompositeDriver() {
			add(new WebcamDefaultDriver());
			add(new IpCamDriver());
		}
	}
	//----选择驱动
	static{
		Webcam.setDriver(new MyCompositeDriver()); 
	}
	
	//----初始化摄像头
	@PostConstruct
    public void init(){
		try {
			for(String cam : HessionServiceConfig.camHost){
				String[] register = cam.split(",");
				IpCamDeviceRegistry.register(new IpCamDevice(register[0],register[1], IpCamMode.PUSH,
						new IpCamAuth(register[2],register[3]))); 	
			} 
		} catch (Exception e){
			e.printStackTrace();
		}
    }
	
	@FXML
	Button btnStartCamera;
	@FXML
	Button btnStopCamera;
	@FXML
	Button btnDisposeCamera;
	@FXML
	Button btnBackToUser;
	@FXML
	Button btnCheck;
	@FXML
	Button takePicture;
	@FXML
	ComboBox<WebCamInfo> cbCameraOptions;
	@FXML
	BorderPane bpWebCamPaneHolder;
	@FXML
	FlowPane fpBottomPane;
	@FXML
	ImageView imgWebCamCapturedImage; 
	@FXML
	ComboBox<UserFaceGroup> groupOptions;
	
	@Autowired
	FaceEngineService faceEngineService;
	@Autowired
	UserFaceInfoService userFaceInfoService; 
	@Autowired
	UserFaceImgService userFaceImgService; 
	
	@Autowired
    private CheckFaceService checkFaceService;
 
	@Lazy
	@Autowired
	private StageManager stageManager;
	
	public static Long groupId = 1L;
	public static Webcam selWebCam = null;
	public static boolean stopCamera = false;
	
	private ObjectProperty<Image> imageProperty = new SimpleObjectProperty<Image>();
	private LinkedBlockingQueue<BufferedImage> checkQueue = new LinkedBlockingQueue<>(50);
	private LinkedBlockingQueue<BufferedImage> takeQueue = new LinkedBlockingQueue<>(10);
	
	private String cameraListPromptText = "选择摄像头";
	private String groupListPromptText = "选择人员分组";
	@FXML
	private Pane facePane; 
	
	@Override
	public void initialize(URL arg0, ResourceBundle arg1){

		fpBottomPane.setDisable(false); 
		btnBackToUser.setDisable(false);
		selectCam(); 
		selectGroup();
		setCamShow(); 
		showCheckedFace();
//		isScanRunning = true; 
//		DaemonExcutor.serviceScan.execute(new ScanFace(faceQueue,count,faceEngineService,faceOne,faceTwo,faceThree,faceFour,faceFive));
		ExcutorUtil.isTakeRunning = true;
		ExcutorUtil.tokePool.execute(new TakeFace(takeQueue,this,userFaceInfoService)); 
		loadUserDetails();
		setColumnProperties(); 
	}
	
	private void selectGroup(){
		ObservableList<UserFaceGroup> groupOption = FXCollections.observableArrayList(
				UserFaceGroup.builder().id(1L).name("特殊人").build(), UserFaceGroup.builder().id(2L).name("普通人").build());
		groupOptions.setItems(groupOption);
		groupOptions.setPromptText(groupListPromptText);
		groupOptions.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<UserFaceGroup>(){
			@Override
			public void changed(ObservableValue<? extends UserFaceGroup> arg0, UserFaceGroup old,
					UserFaceGroup newGroup){
				if (newGroup != null){
					System.out.println("所属组: " + newGroup.getName());
					initializeGroup(newGroup);
				}
			}
		});
	}
	private void selectCam(){
		ObservableList<WebCamInfo> options = FXCollections.observableArrayList();
		int webCamCounter = 0;
		for (Webcam webcam : Webcam.getWebcams()){
			options.add(WebCamInfo.builder().webCamIndex(String.valueOf(webCamCounter++)).webCamName(webcam.getName()).build());
		}
		cbCameraOptions.setItems(options);
		cbCameraOptions.setPromptText(cameraListPromptText);
		cbCameraOptions.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<WebCamInfo>(){
			@Override
			public void changed(ObservableValue<? extends WebCamInfo> arg0, WebCamInfo old, WebCamInfo newCam){
				if (newCam != null) {
					System.out.println("摄像头索引：" + newCam.getWebCamIndex() + ": 摄像头名称:" + newCam.getWebCamName());
					initializeWebCam(newCam.getWebCamIndex());
				}
			}
		});
	}
	
	protected void setCamShow(){
		Platform.runLater(new Runnable(){
			@Override
			public void run() {
				double height = imgWebCamCapturedImage.getFitHeight();
				double width = imgWebCamCapturedImage.getFitWidth();
				imgWebCamCapturedImage.setFitHeight(height);
				imgWebCamCapturedImage.setFitWidth(width);
				imgWebCamCapturedImage.prefHeight(height);
				imgWebCamCapturedImage.prefWidth(width);
				imgWebCamCapturedImage.setPreserveRatio(true); 
			}
		}); 
	}

	protected void initializeGroup(final UserFaceGroup webCamIndex){
		groupId = webCamIndex.getId();
	}

	protected void initializeWebCam(final String webCamIndex){

		Task<Void> webCamIntilizer = new Task<Void>(){

			@Override
			protected Void call() throws Exception{
				//selWebCam.setViewSize(new Dimension(320, 240));
				if (selWebCam == null){
					selWebCam = Webcam.getWebcams().get(Integer.valueOf(webCamIndex));
					selWebCam.open();
				} else {
					closeCamera();
					selWebCam = Webcam.getWebcams().get(Integer.valueOf(webCamIndex));
					selWebCam.open();
				}
				startWebCamStream();
				return null;
			}

		};

		new Thread(webCamIntilizer).start();
		fpBottomPane.setDisable(false);
		btnStartCamera.setDisable(true);
	}

	protected void startWebCamStream(){

		stopCamera = false;
		Task<Void> task = new Task<Void>(){

			@Override
			protected Void call(){

				final AtomicReference<WritableImage> ref = new AtomicReference<>();  
				BufferedImage img = null;
				//int countDrow = 0;
				int countCheck = 0; 
				while(!stopCamera){
					try { 
						if((img = selWebCam.getImage()) != null){
							//img = faceEngineService.drow(img);
							if(++countCheck > 1000){
								countCheck = 0;
								if(ExcutorUtil.toCheck){  
									checkQueue.offer(copyImg(img));
								}
								//faceQueue.offer(copyImg(img));
							} 
							
							if(ExcutorUtil.toTakePicture){
								takeQueue.offer(copyImg(img)); 
							}  
//							long startTime=System.currentTimeMillis();
							
							 
//							if(++countDrow > 10){
//								countDrow = 0;  
//								faceEngineService.drowFace(img); 
//							}
							
							ref.set(SwingFXUtils.toFXImage(img,null));
							img.flush();
							
							Platform.runLater(new Runnable(){
								@Override
								public void run(){
									imageProperty.set(ref.get()); 
								}
							});
//							System.out.println("当前程序耗时："+(System.currentTimeMillis()-startTime)+"ms");
							
						}
					} catch (Exception e){
						e.printStackTrace();
					}
				}
				return null;
			}
		};
		ExcutorUtil.executorService.execute(task);
		imgWebCamCapturedImage.imageProperty().bind(imageProperty); 
	}  
	
	/**复制*/
	public BufferedImage copyImg(BufferedImage img){  
		BufferedImage checkImg = new BufferedImage(img.getWidth(),img.getHeight(),img.getType() == 0 ? 5 : img.getType());
		checkImg.setData(img.getData());
		return checkImg;
	}
	
	public static void closeCamera(){
		stopCamera = true;
		if (selWebCam != null){
			selWebCam.close(); 
		}
	}

	public void stopCamera(ActionEvent event){
		stopCamera = true;
		btnStartCamera.setDisable(false);
		btnStopCamera.setDisable(true);
	}

	public void startCamera(ActionEvent event){
		stopCamera = false;
		startWebCamStream();
		btnStartCamera.setDisable(true);
		btnStopCamera.setDisable(false);
	}

	public void disposeCamera(ActionEvent event){
		stopCamera = true;
		closeCamera();
		btnStopCamera.setDisable(true);
		btnStartCamera.setDisable(true);
	}

	public void backToUser(ActionEvent event){
		stopCamera = true; 
		ExcutorUtil.isScanRunning = false;
		ExcutorUtil.isTakeRunning = false;
		stopCamera(event);
		stageManager.switchScene(FxmlView.USER);
	} 
	
	public void savePicture(ActionEvent event){
		ExcutorUtil.toTakePicture = true;
	}
	
	@FXML
	private Button startSacnBtn;
	@FXML
	private Button stopSacnBtn;
	@FXML
	private TextField passRate;
	
	public AtomicInteger hasCheckedTimes = new AtomicInteger(0);
	public void startScan(ActionEvent event){
		try {
			String pass = passRate.getText();
			if(StringUtils.isNotBlank(pass)){
				if(Validator.isNumber(pass)){
					ExcutorUtil.passRate = Integer.valueOf(pass);
					ExcutorUtil.toCheck = true;
					startSacnBtn.setDisable(true);
					startSacnBtn.setText("进行中...");
					stopSacnBtn.setDisable(false);
					passRate.setEditable(false);
					passRate.setText(ExcutorUtil.passRate+""); 
					checkFaceService.changePassRate(Integer.valueOf(pass));
				}else{
					passRate.setEditable(true);
					passRate.setText("请输入数字"); 
				}
			}else{
				ExcutorUtil.toCheck = true;
				startSacnBtn.setDisable(true);
				startSacnBtn.setText("进行中...");
				stopSacnBtn.setDisable(false);
				passRate.setText(ExcutorUtil.passRate+"");
				passRate.setEditable(false);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		ExcutorUtil.serviceSaveImg.execute(new SaveFaceImg(checkQueue,userFaceImgService));
		ExcutorUtil.serviceCheck.execute(new CheckFace(this,checkFaceService,userFaceInfoService,hasCheckedTimes,faceOne,faceTwo,faceThree,faceFour,faceFive));
		 
	}
	
	public void stopScan(ActionEvent event){ 
		ExcutorUtil.toCheck = false;
		startSacnBtn.setText("开始检测");
		stopSacnBtn.setText("已经结束");
		startSacnBtn.setDisable(false);
		stopSacnBtn.setDisable(true);
		passRate.setEditable(true);
//		DaemonExcutor.serviceCheck.shutdown();
//		 
//    	boolean isFlag=true;
//    	while(isFlag){  
//            if(DaemonExcutor.serviceCheck.isTerminated()){  
//            	isFlag = false;
//	            System.out.println("所有的子线程都结束了！");  
//	            break;  
//            }else{
//            	//DaemonExcutor.serviceCheck.shutdownNow();
//            	System.out.println("--------还未结束-----------------");
//            }
//            try {
//				Thread.sleep(10000);
//			} catch (InterruptedException e){ 
//				e.printStackTrace();
//			}    
//         }
	}
	
	@FXML
	private TableView<UserFaceInfo> userTable; 
	@FXML
	private TableColumn<UserFaceInfo, String> colName; 
	@FXML
	private TableColumn<UserFaceInfo, Long> colUserId; 
	@FXML
	private TableColumn<UserFaceInfo, String> colAge; 
	@FXML
	private TableColumn<UserFaceInfo, String> colGender;
	@FXML
	private TableColumn<UserFaceInfo, String> checkState;
	@FXML
	private Pagination userFacePage;
	@FXML
	private TextField nameText; 
	@FXML
	private Button userSearch;
	@FXML
	private MenuItem delUser;
	
	
	
	@FXML
	private void delUser(ActionEvent event) {
		
		List<UserFaceInfo> users = userTable.getSelectionModel().getSelectedItems();

		Alert alert = new Alert(AlertType.CONFIRMATION);
		alert.setTitle("确定框");
		alert.setHeaderText(null);
		alert.setContentText("确定是否删除?");
		Optional<ButtonType> action = alert.showAndWait();

		if (action.get() == ButtonType.OK)
			userFaceInfoService.deleteInBatch(users); 
		search();
		
	}
	private ObservableList<UserFaceInfo> userList = FXCollections.observableArrayList();
	
	private void loadUserDetails(){ 
		userFacePage.setPageFactory(param -> createPage(param,"")); 
	}
	
	private void setColumnProperties(){ 
		colUserId.setCellValueFactory(new PropertyValueFactory<>("id"));
		colName.setCellValueFactory(new PropertyValueFactory<>("name"));
		colGender.setCellValueFactory(new PropertyValueFactory<>("genderName"));
		colAge.setCellValueFactory(new PropertyValueFactory<>("age"));
		checkState.setCellValueFactory(new PropertyValueFactory<>("checkState"));
		//colEdit.setCellFactory(cellFactory);
	}
	
	public void search(){
		String userName = nameText.getText();
		userFacePage.setPageFactory(param -> createPage(param,userName)); 
	}
	
	public Label createPage(int pageIndex,String name){
		Page<UserFaceInfo> page = new Page<>();
		page.setCurrent(++pageIndex);
		Page<UserFaceInfo> users = userFaceInfoService.selectPage(page, new EntityWrapper<UserFaceInfo>().like(StringUtils.isNotBlank(name),"name", name).orderBy("id",false).orderBy("checked"));
		userFacePage.setPageCount(users.getPages()); 
		userList.clear();
		userList.addAll(users.getRecords()); 
		userTable.setItems(userList);  
		return new Label();
	}
	
	
	int currentIndex = 0;  // 当前id
    Image[] images = new Image[1];
    String[] imageUrls = {"/images/scan.gif"};
    private ImageView faceOne = new ImageView();
    private ImageView faceTwo = new ImageView();
    private ImageView faceThree = new ImageView();
    private ImageView faceFour = new ImageView();
    private ImageView faceFive = new ImageView();
    
	private void showCheckedFace(){ 
        // 循环创建无法进行图片指定  
//      ParallelTransition parallelTransition=new ParallelTransition();
//      for(int i=0;i<6;i++){
//        	ImageView faceImg = new ImageView();
//        	setImg(faceImg);
//        	facePane.getChildren().add(faceImg);
//        	parallelTransition.getChildren().add(build(faceImg,i * 1140));
//        	
//      }
		setImg(faceOne,faceTwo,faceThree,faceFour,faceFive); 
        //创建矩形，起点在x=100,y=50的位置 
  		facePane.getChildren().addAll(faceOne,faceTwo,faceThree,faceFour,faceFive); 
        //并行执行动画
        ParallelTransition parallelTransition=new ParallelTransition(
        		build(faceOne,0),
        		build(faceTwo,1140),
        		build(faceThree,2280),
        		build(faceFour,3420),
        		build(faceFive,4560));
         
        parallelTransition.setCycleCount(Timeline.INDEFINITE);
        parallelTransition.play();

	}
	public void setImg(ImageView... imgs){
		for(ImageView img : imgs){
			images[0] = new Image(getClass().getResourceAsStream(imageUrls[0])); 
	        int width = 250;
	        int height = 180;
	        // 保持比例，适应窗口显示 
	        img.setLayoutX(10);
	        img.setLayoutY(690);
	        img.setFitWidth(width);
	        img.setFitHeight(height);
	        img.setImage(images[currentIndex]);
		} 
	}
	
	public PathTransition build(ImageView img,long time){
		Path path=new Path();
        path.getElements().add(new MoveTo(90,0));
        path.getElements().add(new VLineTo(-800));
        PathTransition pt=new PathTransition();
        pt.setRate(0.07);
        pt.setPath(path);//设置路径
        pt.setNode(img);//设置物体
        if(time != 0){
        	pt.setDelay(Duration.millis(time));
        } 
        //设置周期性，无线循环
        pt.setCycleCount(Timeline.INDEFINITE);
        pt.setAutoReverse(false);//自动往复 
        return pt;
	}
}
